
import datetime as dt
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Point import Point

from bqgraph.qt import QtCore,pyqtSignal

########################################################################
# 十字光标支持
########################################################################
class CrossHair(QtCore.QObject):
    """
    此类给pg.PlotWidget()添加crossHair功能,PlotWidget实例需要初始化时传入
    """
    # signal = pyqtSignal(type(tuple([])))
    signal = QtCore.Signal(float, float)
    signalInfo = QtCore.Signal(float, float)
    signalChartCountChanged = QtCore.Signal(int)


    def __init__(self, parent, master, sync_num=2):
        """Constructor"""
        self.__view = parent
        self.master = master
        super(CrossHair, self).__init__()

        self.xAxis = 0
        self.yAxis = 0
        # 需要共用十字光标的绘图区域数
        self.sync_num = sync_num
        self.visible = True
        self.data = None

        self.yAxises = [0 for i in range(self.sync_num)]
        self.leftX = [0 for i in range(self.sync_num)]
        self.showHLine = [False for i in range(self.sync_num)]
        self.textPrices = [pg.TextItem('', anchor=(1, 1)) for i in range(self.sync_num)]
        self.views = [parent.centralWidget.getItem(i + 1, 0) for i in range(self.sync_num)]
        self.rects = [self.views[i].sceneBoundingRect() for i in range(self.sync_num)]
        self.vLines = [pg.InfiniteLine(angle=90, movable=False) for i in range(self.sync_num)]
        self.hLines = [pg.InfiniteLine(angle=0, movable=False) for i in range(self.sync_num)]
        # 保存当前位置
        self.saved_vpos = None
        self.saved_hpos = None
        # mid 在y轴动态跟随最新价显示最新价和最新时间
        self.__textData = pg.TextItem('dataInfo')
        self.__textDate = pg.TextItem('date')
        self.__textInfo = pg.TextItem('lastBarInfo')
        self.__textSig = pg.TextItem('lastSigInfo', anchor=(1, 0))
        self.__textIndicators = pg.TextItem('SAR', anchor=(1, 0))
        self.__textVolume = pg.TextItem('lastBarVolume', anchor=(1, 0))

        self.__textDate.setZValue(2)
        self.__textInfo.setZValue(2)
        self.__textSig.setZValue(2)
        self.__textData.setZValue(2)
        self.__textVolume.setZValue(2)
        self.__textInfo.border = pg.mkPen(color=(230, 255, 0, 255), width=1.2)
        self.__textIndicators.setZValue(2)  # 指标
        self.__textData.border = pg.mkPen(color=(230, 255, 0, 255), width=1.2)

        for i in range(self.sync_num):
            self.textPrices[i].setZValue(2)
            self.vLines[i].setPos(0)
            self.hLines[i].setPos(0)
            self.views[i].addItem(self.vLines[i])
            self.views[i].addItem(self.hLines[i])
            self.views[i].addItem(self.textPrices[i])

        self.views[0].addItem(self.__textInfo, ignoreBounds=True)
        self.views[0].addItem(self.__textSig, ignoreBounds=True)
        self.views[0].addItem(self.__textIndicators, ignoreBounds=True)
        # self.views[1].addItem(self.__textVolume, ignoreBounds=True)
        # self.views[2].addItem(self.__textDate, ignoreBounds=True)

        self.proxy = pg.SignalProxy(self.__view.scene().sigMouseMoved, rateLimit=60, slot=self.__mouseMoved)
        # 跨线程刷新界面支持
        self.signal.connect(self.update)

    def set_sync_num(self, sync_num):
        self.sync_num = sync_num

    # ----------------------------------------------------------------------
    def update(self, x,y):
        """刷新界面显示"""
        xAxis, yAxis = x,y
        xAxis, yAxis = (self.xAxis, self.yAxis) if xAxis is None else (xAxis, yAxis)
        if self.data is None:
            return
        self.moveTo(xAxis, yAxis)

    # ----------------------------------------------------------------------
    def __mouseMoved(self, evt):
        """鼠标移动回调"""
        if self.data is None:
            return
        if not self.visible:
            return
        # print('before __mouseMoved')
        pos = evt[0]
        self.rects = [self.views[i].sceneBoundingRect() for i in range(self.sync_num)]

        for i in range(self.sync_num):
            self.showHLine[i] = False
            if self.rects[i].contains(pos):
                mousePoint = self.views[i].vb.mapSceneToView(pos)
                xAxis = mousePoint.x()
                yAxis = mousePoint.y()
                self.yAxises[i] = yAxis
                self.showHLine[i] = True
                self.moveTo(xAxis, yAxis)

    # ----------------------------------------------------------------------
    def moveTo(self, xAxis, yAxis):
        # print('before moveTo')
        xAxis, yAxis = (self.xAxis, self.yAxis) if xAxis is None else (xAxis, yAxis)
        self.rects = [self.views[i].sceneBoundingRect() for i in range(self.sync_num)]

        if not xAxis or not yAxis:
            return
        self.xAxis = xAxis
        self.yAxis = yAxis
        self.vhLinesSetXY(xAxis, yAxis)
        self.plotPrice(yAxis)
        self.plotDataInfo(xAxis)
        # if self.master.main_graph_type == GRAPH_TYPE_KBAR:
        #     self.plotInfo(xAxis)
        # else:
        #     self.plotDataInfo(xAxis)
        # print('after moveTo')

        # ----------------------------------------------------------------------

    def vhLinesSetXY(self, xAxis, yAxis):
        """水平和竖线位置设置"""
        for i in range(self.sync_num):
            self.vLines[i].setPos(xAxis)
            if self.showHLine[i]:
                self.hLines[i].setPos(yAxis if i == 0 else self.yAxises[i])
            else:
                topLeft = self.views[i].vb.mapSceneToView(QtCore.QPointF(self.rects[i].left(), self.rects[i].top()))
                self.hLines[i].setPos(topLeft.y() + abs(topLeft.y()))

    # ----------------------------------------------------------------------
    def plotPrice(self, yAxis):
        """价格位置设置"""
        for i in range(self.sync_num):
            if self.showHLine[i]:
                rightAxis = self.views[i].getAxis('right')
                rightAxisWidth = rightAxis.width()
                topRight = self.views[i].vb.mapSceneToView(
                    QtCore.QPointF(self.rects[i].right() - rightAxisWidth, self.rects[i].top()))
                self.textPrices[i].setHtml(
                    '<div style="text-align: right;">\
                        <span style="color: yellow; font-size: 12px;">\
                          %0.3f\
                        </span>\
                    </div>' \
                    % (yAxis if i == 0 else self.yAxises[i]))
                self.textPrices[i].setPos(topRight.x(), yAxis if i == 0 else self.yAxises[i])
            else:
                topRight = self.views[i].vb.mapSceneToView(QtCore.QPointF(self.rects[i].right(), self.rects[i].top()))
                self.textPrices[i].setPos(topRight.x(), topRight.y() + abs(topRight.y()))


    # ----------------------------------------------------------------------
    def plotInfo(self, xAxis):
        """
        被嵌入的plotWidget在需要的时候通过调用此方法显示K线信息
        """
        xAxis = round(xAxis)
        # print('xAxis')
        if self.data is None:
            return
        try:
            # 获取K线数据
            tickDatetime = self.data[int(xAxis)]['datetime']
            openPrice = self.data[int(xAxis)]['open']
            closePrice = self.data[int(xAxis)]['close']
            lowPrice = self.data[int(xAxis)]['low']
            highPrice = self.data[int(xAxis)]['high']
            volume = self.data[int(xAxis)]['volume']
            # openInterest = self.data[int(xAxis)]['openInterest']
            preClosePrice = self.data[int(xAxis) - 1]['close']
        except Exception as e:
            # print('error:{} in plotInfo'.format(e))
            return

        if isinstance(tickDatetime, np.datetime64):
            tickDatetime = tickDatetime.astype(str)
            tickDatetime = tickDatetime[:-4]

        if isinstance(tickDatetime, (dt.datetime)):
            datetimeText = dt.datetime.strftime(tickDatetime, '%Y-%m-%d %H:%M:%S')
            dateText = dt.datetime.strftime(tickDatetime, '%Y-%m-%d')
            timeText = dt.datetime.strftime(tickDatetime, '%H:%M:%S')
        elif (isinstance(tickDatetime, (str))):
            datetimeText = tickDatetime
            dateTemp = dt.datetime.strptime(datetimeText, '%Y-%m-%dT%H:%M:%S.%f')
            dateText = dt.datetime.strftime(dateTemp, '%Y-%m-%d')
            timeText = dt.datetime.strftime(dateTemp, '%H:%M:%S')
        else:
            datetimeText = ""
            dateText = ""
            timeText = ""

        # 显示所有的主图技术指标
        html = u'<div style="text-align: right">'
        for sig in self.master.sigData:
            val = self.master.sigData[sig][int(xAxis)]
            col = self.master.sigColor[sig]
            html += u'<span style="color: %s;  font-size: 12px;">&nbsp;&nbsp;%s：%.2f</span>' % (col, sig, val)
        html += u'</div>'
        self.__textSig.setHtml(html)

        # 显示指标
        # if self.master.sarDatas is not None:
        #     # arrow=self.master.sars[int(xAxis)]
        #     self.__textIndicators.setHtml(
        #         '<div style="text-align: center">\
        #             <span style="color: yellow; font-size: 12px;">SAR:%.2f</span>\
        #         </div>' \
        #         % (self.master.sarDatas[int(xAxis)]))

        # 和上一个收盘价比较，决定K线信息的字符颜色
        openText = "%.3f" % openPrice
        closeText = "%.3f" % closePrice
        highText = "%.3f" % highPrice
        lowText = "%.3f" % lowPrice
        cOpen = 'red' if openPrice > preClosePrice else 'green'
        cClose = 'red' if closePrice > preClosePrice else 'green'
        cHigh = 'red' if highPrice > preClosePrice else 'green'
        cLow = 'red' if lowPrice > preClosePrice else 'green'

        self.__textInfo.setHtml(
            """<div style="text-align: center; background-color:#000;height:auto ">
                <span style="color: white;  font-size: 12px;">日期</span><br>
                <span style="color: yellow; font-size: 12px;">%s</span><br>
                <span style="color: white;  font-size: 12px;">时间</span><br>
                <span style="color: yellow; font-size: 12px;">%s</span><br>
                <span style="color: white;  font-size: 12px;">开盘</span><br>
                <span style="color: %s;     font-size: 12px;">%s</span><br>
                <span style="color: white;  font-size: 12px;">最高</span><br>
                <span style="color: %s;     font-size: 12px;">%s</span><br>
                <span style="color: white;  font-size: 12px;">最低</span><br>
                <span style="color: %s;     font-size: 12px;">%s</span><br>
                <span style="color: white;  font-size: 12px;">收盘</span><br>
                <span style="color: %s;     font-size: 12px;">%s</span><br>
                <span style="color: white;  font-size: 12px;">成交量</span><br>
                <span style="color: yellow; font-size: 12px;">%.3f</span><br>
            </div>""" % (dateText, timeText, cOpen, openText, cHigh, highText,
               cLow, lowText, cClose, closeText, volume))
        # print(self.__textInfo)
        self.__textDate.setHtml(
            '<div style="text-align: center">\
                <span style="color: yellow; font-size: 12px;">%s</span>\
            </div>' \
            % (datetimeText))

        self.__textVolume.setHtml(
            '<div style="text-align: right">\
                <span style="color: white; font-size: 12px;">VOL : %.3f</span>\
            </div>' \
            % (volume))

        # K线子图，左上角显示
        leftAxis = self.views[0].getAxis('left')
        leftAxisWidth = leftAxis.width()
        topLeft = self.views[0].vb.mapSceneToView(
            QtCore.QPointF(self.rects[0].left() + leftAxisWidth, self.rects[0].top()))
        x = topLeft.x()
        y = topLeft.y()
        # print(x,y)
        self.__textInfo.setPos(x, y)

        # K线子图，左上角显示
        leftAxis = self.views[0].getAxis('left')
        leftAxisWidth = leftAxis.width()
        topLeft = self.views[0].vb.mapSceneToView(
            QtCore.QPointF(self.rects[0].left() + leftAxisWidth, self.rects[0].top()))
        x = topLeft.x()
        y = topLeft.y()
        self.__textSig.setPos(x, y)

        # K线子图，右上角显示
        rightAxis = self.views[0].getAxis('right')
        rightAxisWidth = rightAxis.width()
        topRight = self.views[0].vb.mapSceneToView(
            QtCore.QPointF(self.rects[0].right() - rightAxisWidth, self.rects[0].top()))
        x = topRight.x()
        y = topRight.y()
        self.__textIndicators.setPos(x, y)

        # 成交量子图，右上角显示
        rightAxis = self.views[1].getAxis('right')
        rightAxisWidth = rightAxis.width()
        topRight = self.views[1].vb.mapSceneToView(
            QtCore.QPointF(self.rects[1].right() - rightAxisWidth, self.rects[1].top()))
        x = topRight.x()
        y = topRight.y()
        self.__textVolume.setPos(x, y)

        # X坐标时间显示
        rectTextDate = self.__textDate.boundingRect()
        rectTextDateHeight = rectTextDate.height()
        bottomAxis = self.views[2].getAxis('bottom')
        bottomAxisHeight = bottomAxis.height()
        bottomRight = self.views[2].vb.mapSceneToView(QtCore.QPointF(self.rects[2].width(),
                                                                     self.rects[2].bottom() - (
                                                                             bottomAxisHeight + rectTextDateHeight)))
        # 修改对称方式防止遮挡
        if xAxis > self.master.x_center:
            self.__textDate.anchor = Point((1, 0))
        else:
            self.__textDate.anchor = Point((0, 0))
        self.__textDate.setPos(xAxis, bottomRight.y())

    def plotDataInfo(self, xAxis):
        """
        被嵌入的plotWidget在需要的时候通过调用此方法显示K线信息
        """
        row_no = int(round(xAxis))
        # print(row_no)
        if self.data is None:
            return
        if not self.master or not self.master.fields_name:
            return
        fields_name = self.master.fields_name
        if row_no<0:
            row_no=0
        if row_no>len(self.data)-1:
            row_no=-1

        # print(fields_name)
        # datetimeText = ""
        # dateText = ""
        # timeText = ""
        # try:
        #     # 获取K线数据
        #     tickDatetime = self.data[row_no]['datetime']
        #
        # except Exception as e:
        #     # print('error:not found the datetime field  in plotInfo--{}'.format(e))
        #     return
        #
        # if datetimeText:
        #     if isinstance(tickDatetime, np.datetime64):
        #         tickDatetime = tickDatetime.astype(str)
        #         tickDatetime = tickDatetime[:-4]
        #
        #     if isinstance(tickDatetime, (dt.datetime)):
        #         datetimeText = dt.datetime.strftime(tickDatetime, '%Y-%m-%d %H:%M:%S')
        #         dateText = dt.datetime.strftime(tickDatetime, '%Y-%m-%d')
        #         timeText = dt.datetime.strftime(tickDatetime, '%H:%M:%S')
        #     elif (isinstance(tickDatetime, (str))):
        #         datetimeText = tickDatetime
        #         dateTemp = dt.datetime.strptime(datetimeText, '%Y-%m-%dT%H:%M:%S.%f')
        #         dateText = dt.datetime.strftime(dateTemp, '%Y-%m-%d')
        #         timeText = dt.datetime.strftime(dateTemp, '%H:%M:%S')
        #         datetimeText = dt.datetime.strptime(datetimeText, '%Y-%m-%dT%H:%M:%S')

        info = '<div style="text-align: center; background-color:#000;height:auto ">'
        # if dateText and timeText:
        #     info += """<span style="color: white;  font-size: 12px;">日期:</span>
        #         <span style="color: yellow; font-size: 12px;">{}</span>
        #         <span style="color: white;  font-size: 12px;">时间:</span>
        #         <span style="color: yellow; font-size: 12px;">{}</span><br>""".format(dateText, timeText)
        name_value = ''
        for fn in fields_name:
            if fn!='datetime':
                name_value += """<span style="color: white;  font-size: 12px;">{}:</span>
                <span style="color: yellow; font-size: 12px;">{}</span><br>""".format(fn, self.data[row_no][fn])
        info += name_value
        info += '</div>'
        # print('name_value',name_value)
        self.__textInfo.setHtml(info)
        # 主图，左上角显示
        leftAxis = self.views[0].getAxis('left')
        leftAxisWidth = leftAxis.width()
        topLeft = self.views[0].vb.mapSceneToView(
            QtCore.QPointF(self.rects[0].left() + leftAxisWidth, self.rects[0].top()))
        x = topLeft.x()
        y = topLeft.y()
        # print(x, y)
        self.__textInfo.setPos(x+1, y)

        # self.__textDate.setHtml(
        #     '<div style="text-align: center">\
        #         <span style="color: yellow; font-size: 12px;">%s</span>\
        #     </div>' \
        #     % (datetimeText))
        # X坐标时间显示
        rectTextDate = self.__textDate.boundingRect()
        rectTextDateHeight = rectTextDate.height()
        bottomAxis = self.views[0].getAxis('bottom')
        bottomAxisHeight = bottomAxis.height()
        bottomRight = self.views[0].vb.mapSceneToView(QtCore.QPointF(self.rects[0].width(),
                                                                     self.rects[0].bottom() - (
                                                                             bottomAxisHeight + rectTextDateHeight)))
        # 修改对称方式防止遮挡
        if row_no > self.master.x_center:
            self.__textDate.anchor = Point((1, 0))
        else:
            self.__textDate.anchor = Point((0, 0))
        self.__textDate.setPos(row_no, bottomRight.y())

    def show(self):
        self.visible = True
        if self.saved_hpos:
            for i, line in enumerate(self.hLines):
                line.setValue(self.saved_hpos[i])
        if self.saved_vpos:
            for i, line in enumerate(self.vLines):
                line.setValue(self.saved_vpos[i])

    def hide(self):
        self.visible = False
        self.saved_hpos = [line.value() for line in self.hLines]
        self.saved_vpos = [line.value() for line in self.vLines]
        self.__textInfo.setHtml('')
        self.__textData.setHtml('')
        if self.saved_hpos:
            for i, line in enumerate(self.hLines):
                line.setValue(0)
        if self.saved_vpos:
            for i, line in enumerate(self.vLines):
                line.setValue(0)
